/*
 * CharacterNGramCount.java
 *
 * Created on November 8, 2007, 9:24 AM
 *
 */
package EstimatorPackage.NGramChar;

import gnu.trove.TIntIntHashMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author Martin Haulrich
 */
public class CharacterNGramCount {

    /**
     * @TODO After a quick glance it seems that this variable is not being used for anything. Check this and remove it if it is the case.
     */
    final Set<Character> chars;

    final int N;

    Map<Integer, Map<String, Integer>> ngrams;

    //Map<Integer, Integer> ngramcount;
TIntIntHashMap ngramcount;

    /** Constructor */
    public CharacterNGramCount(Set<Character> chars, List<String> words, int N) {
        this.chars = new HashSet<Character>(chars);
        this.N = N;
        ngrams = new HashMap<Integer, Map<String, Integer>>(N);
        //ngramcount = new HashMap<Integer, Integer>(N);
        ngramcount = new TIntIntHashMap(N);

        for (int n = 1; n <= N; n++) {
            Map<String, Integer> currentN = new HashMap<String, Integer>();
            int count = 0;
            for (Iterator<String> it = words.iterator(); it.hasNext();) {
                String word = it.next();
                /**
                 * @TODO I think the amount of added start and stop symbols are wrong because there are fewer 2-grams than all other n-grams. I think that for the hmm-model to work there should be eqylly many of all Maybe do it like in WordNGramCount
                 */
                String stops = "";
                for (int j = 1; j < Math.max(n, 2); j++) {
                    stops = stops + "$";
                }
                String starts = "";
                for (int j = 1; j < Math.max(n, 2); j++) {
                    starts = starts + "^";
                }

                word = starts + word + stops;
                for (int i = 0; i < word.length() - n + 1; i++) {
                    String ngram = word.substring(i, i + n);
                    if (currentN.containsKey(ngram)) {
                        currentN.put(ngram, currentN.get(ngram) + 1);
                    } else {
                        currentN.put(ngram, 1);

                    }

                    count++;

                }
            }

            ngramcount.put(n, count);

            ngrams.put(n, currentN);

        }

    }


    public int getVocabSize(int N) {
        //return (int) Math.pow(chars.size(),N);
        return ngrams.get(N).size();
    }


    public int getCount(String ngram) {
        if (ngram.length() > N) {
            System.err.println("This object only has up to " + N + "-grams.");
            System.err.println("Returning O-count");
            return 0;
        } else {
            //  System.err.println("CharNGram, getCount: '" + ngram + "'");
            Map<String, Integer> currentN = ngrams.get(ngram.length());
            if (currentN.containsKey(ngram)) {
                return currentN.get(ngram);
            } else {
                return 0;
            }
        }
    }


    public Set<String> getNGrams(int N) {
        return ngrams.get(N).keySet();
    }


    public int getNCount(int N) {
//        Map<String,Integer> tmp = ngrams.get(N);
//        int sum=0;
//        for (Iterator<String> it = tmp.keySet().iterator(); it.hasNext(); ) {
//            String key = it.next();
//            sum=sum+tmp.get(key);
//        }
//        if ((sum-ngramcount.get(N))!=0) {
//     //       System.err.println("getNCount " + sum + "  " + ngramcount.get(N));
//        }

        return ngramcount.get(N);
    }


    public int getNDifferent(int N) {
        return ngrams.get(N).size();
    }


    public int getN() {
        return N;
    }


    public void printAll() {
        for (int n = 1; n <= N; n++) {
            Map<String, Integer> currentN = ngrams.get(n);
            System.out.println("--- " + ngramcount.get(n) + " " + n + "-grams, " + currentN.size() + " different");
            for (Iterator<String> it = currentN.keySet().iterator(); it.hasNext();) {
                String ngram = it.next();
                System.out.println(ngram + "\t" + currentN.get(ngram));

            }
        }
    }
}
